// This file was renamed on 11-29-06 from AbstractDatabaseDataAccessor.cs to AbstractODBCDataAccessor.cs

using System;
using System.Collections.Generic;
using System.Text;

using System.Data;
using Microsoft.Data.Odbc;
using System.Data.Common;

using Sandia.MVCFramework.Common;
using Sandia.MVCFramework.Data;
using Sandia.MVCFramework.Request;

namespace Sandia.MVCFramework.DataAccessor
{
    /// <summary>
    /// Abstract implementation of a data accessor for ODBC data sources
    /// </summary>
    public abstract class AbstractODBCDataAccessor: AbstractStandardDataAccessor
    {
        /// <summary>
        /// Whether or not the object has been disposed of yet (with a call to dispose)
        /// </summary>
        protected bool disposed = false;

        private IDbConnection dbConn;
        private string connectionString;

        /// <summary>
        /// Create a new connection to a server side object. 
		/// </summary>
		/// <param name="ConnectionString">The required connection string</param>
        /// <remarks>
        /// The required conneciton string is a string that contains the 
        /// necessary parameters for accessing the database through the 
        /// Microsoft odbc dll. It is usually just the name of the database
        /// </remarks>
        public AbstractODBCDataAccessor(string ConnectionString)
        {
            this.connectionString = ConnectionString;
            try
            {
                openDBConnection();
            }
            catch 
            {
                LoggingTools.SendToLog(
                    "AbstractODBCDataAccessor: Unable to Open Database Connection",
                    LoggingCategories.ERROR,
                    100);
            }
            
            confirmDBConnection();
        }

        #region Processing and Parsing of Control commands and Requests

        /// <summary>
        /// Send a new database query to a server side object. 
        /// </summary>
        /// <param name="sql">The required request string</param>
        /// <returns>The database data returned from the query</returns>
        protected OdbcDataReader executeCommand(string sql)
        {
            IDbCommand command;
            OdbcDataReader returnValue = null;
            if (GetDBConnectionStatus().Equals(ConnectionState.Open))
            {
                command = new OdbcCommand(sql, (OdbcConnection)dbConn);
                returnValue = (OdbcDataReader)command.ExecuteReader();
            }

            return returnValue;

        }

        #endregion

        
        #region DataBase Primitive Methods
        
        /// <summary>
        /// Determine the database connection state
        /// </summary>
        /// <returns></returns>
        public ConnectionState GetDBConnectionStatus()
        {
            return dbConn.State;
        }

        /// <summary>
        /// Gets the name of the database
        /// </summary>
        /// <returns></returns>
        public string GetDBName()
        {
            if (dbConn.State.Equals(ConnectionState.Open))
            {
                return dbConn.Database;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Open the database connection
        /// </summary>
        protected void openDBConnection() 
		{
			dbConn= new OdbcConnection(connectionString);
            try
            {
                dbConn.Open();
            }
            catch
            {
                LoggingTools.SendToLog(
                    "openDBConnection: Unable to Open Database Connection",
                    LoggingCategories.ERROR,
                    100);
            }
		}

		/// <summary>
		/// Check that the DB connection is open. If not, try to open it.
		/// </summary>
		protected void confirmDBConnection() 
		{
			if (dbConn==null || !dbConn.State.Equals(ConnectionState.Open)) 
			{
				try 
				{
					dbConn.Close();
				} 
				catch
                {
                    LoggingTools.SendToLog(
                        "confirmDBConnection: Unable to Close Database Connection",
                        LoggingCategories.ERROR,
                        100);
                }
				try 
				{
					openDBConnection();
				} 
				catch
                {
                    LoggingTools.SendToLog(
                        "confirmDBConnection: Unable to Open Database Connection",
                        LoggingCategories.ERROR,
                        100);
				}
			}
		}
		
        /// <summary>
        /// Closes the database connection
        /// </summary>
        protected void CloseDBConnection () 
		{
			try 
			{
				dbConn.Close();
			} 
			catch
            {
                LoggingTools.SendToLog(
                    "CloseDBConnection: Unable to Close Database Connection",
                    LoggingCategories.ERROR,
                    100);
			}
		}

		#endregion

        #region IDisposable Members
        // IDisposable implementation using Dispose Pattern adapted from
        // "Improving .NET Application Performance and Scalability" by 
        // Microsoft, pp. 200-203

        /// <summary>
        /// Common cleanup functionality - used to handle disposing
        /// and finalization; by default nothing to clean up unless
        /// overriden by child class
        /// </summary>
        /// <param name="disposing">True if being called by
        /// Dispose() or directly from object itself, false if being
        /// called by finalizer</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Dispose time code - i.e. free managed objects
                // Nothing to do
            }

            // Finalize time code - i.e. free unmanaged objects & resources
            this.CloseDBConnection();

            // Mark us disposed
            this.disposed = true;
        }

        /// <summary>
        /// Allows the filter to clean up after itself and close off any 
        /// open resources; much more efficient to call this explicitly
        /// than to have garbage collector call finalizer
        /// </summary>
        public override void Dispose()
        {
            // Check to see if Dispose had already been called
            if (!disposed)
            {
                // Call the overridden cleanup method that contains common
                // cleanup code; pass true to indicate that it is called
                // from Dispose
                this.Dispose(true);

                // Prevent subsequent finalization of this object.  This
                // is not needed because both managed and unmanaged resources
                // were explicitly released through the call to this method
                GC.SuppressFinalize(this);
            }
        }

        #endregion
    }
}

